package script

import (
	"context"
	"fmt"
	"math"
	"path/filepath"
	"sync"
	"tinyGW/app/models"
	"tinyGW/pkg/plugin/io"

	"go.uber.org/fx"

	"github.com/yuin/gluamapper"
	lua "github.com/yuin/gopher-lua"
	"go.uber.org/zap"
)

type (
	Runner interface {
		Open(filename string) error
		Close()
		GenerateGetRealVariables(address string, step int) (data []byte, result bool, continued bool)
		DeviceCustomCmd(sAddr string, cmdName string, cmdParam string, step int) ([]byte, bool, bool)
		AnalysisRx(sAddr string, variables []models.DeviceProperty, rxBuf []byte, rxBufCnt int, tempVariables *[]models.DeviceProperty) bool
		AnalysisRxEnhanced(sAddr string, variables []models.DeviceProperty, rxBuf []byte, rxBufCnt int) AnalysisRxResult

		// 协议检测：判断数据是否匹配该协议
		DetectProtocol(data []byte) bool

		// 提取设备地址
		ExtractDeviceAddress(data []byte) string

		// 新增：处理主动上报事件
		HandleActiveReport(deviceAddr string, data []byte, variables []models.DeviceProperty) (EventResult, error)

		// 检查Lua脚本是否实现了某个函数
		HasFunction(funcName string) bool

		// 获取协议名称
		GetProtocolName() string
	}

	// EventResult 事件处理结果
	EventResult struct {
		Success      bool                   // 是否处理成功
		NeedResponse bool                   // 是否需要响应
		Response     []byte                 // 响应数据
		DeviceData   map[string]interface{} // 设备数据（用于更新设备状态）
		EventType    string                 // 事件类型（如 "login", "heartbeat", "data", "alarm"）
		ShouldReport bool                   // 是否应该上报到云端
	}

	luaRunner struct {
		lState     *lua.LState
		filename   string
		isValid    bool
		mutex      sync.RWMutex
		bufferPool sync.Pool // 字节缓冲池
	}

	// LuaResult 统一的Lua调用结果结构
	LuaResult struct {
		Status   string  `json:"Status"`
		Variable []*byte `json:"Variable"`
	}

	// LuaVariable Lua变量模板
	LuaVariable struct {
		Index   int         `json:"Index"`
		Name    string      `json:"Name"`
		Label   string      `json:"Label"`
		Type    string      `json:"Type"`
		Value   interface{} `json:"Value"`
		Explain string      `json:"Explain"`
	}

	// LuaVariableMap Lua变量映射模板（增强版，支持帧类型和响应）
	LuaVariableMap struct {
		Status       string         `json:"Status"`       // "0"=成功, "1"=失败
		Variable     []*LuaVariable `json:"Variable"`     // 解析出的变量
		FrameType    string         `json:"FrameType"`    // 帧类型：login/heartbeat/data/response/command（可选）
		NeedResponse bool           `json:"NeedResponse"` // 是否需要响应（可选）
		Response     []interface{}  `json:"Response"`     // 响应数据字节数组（可选）
	}
)

func NewLuaRunner() Runner {
	return &luaRunner{
		lState:  nil,
		isValid: false,
		bufferPool: sync.Pool{
			New: func() interface{} {
				return make([]byte, 0, 256) // 预分配256字节容量
			},
		},
	}
}

func (l *luaRunner) Open(filename string) error {
	l.mutex.Lock()
	defer l.mutex.Unlock()

	// 如果已经打开了相同的文件，直接返回
	if l.lState != nil && l.filename == filename && l.isValid {
		return nil
	}

	// 关闭旧的状态
	if l.lState != nil {
		l.lState.Close()
	}

	// 创建新的Lua状态
	l.lState = lua.NewState()
	l.filename = filename
	l.isValid = false

	// 构建脚本路径
	path := filepath.Join(io.GetCurrentPath(), "plugin", filename, filename+".lua")

	// 加载脚本文件
	if err := l.lState.DoFile(path); err != nil {
		zap.S().Errorf("Failed to load Lua script: %v, path: %s", err, path)
		l.lState.Close()
		l.lState = nil
		return err
	}

	// 注册全局函数
	l.registerGlobalFunctions()
	l.isValid = true

	return nil
}

func (l *luaRunner) Close() {
	l.mutex.Lock()
	defer l.mutex.Unlock()

	if l.lState != nil {
		l.lState.Close()
		l.lState = nil
	}
	l.isValid = false
	l.filename = ""
}

// registerGlobalFunctions 注册全局函数
func (l *luaRunner) registerGlobalFunctions() {
	l.lState.SetGlobal("GetCRCModbus", l.lState.NewFunction(GetCRCModbus))
	l.lState.SetGlobal("CheckCRCModbus", l.lState.NewFunction(CheckCRCModbus))
	l.lState.SetGlobal("GetCRCModbusLittleEndian", l.lState.NewFunction(GetCRCModbusLittleEndian))
}

// isStateValid 检查Lua状态是否有效
func (l *luaRunner) isStateValid() bool {
	l.mutex.RLock()
	defer l.mutex.RUnlock()
	return l.lState != nil && l.isValid
}

// callLuaFunction 统一的Lua函数调用方法
func (l *luaRunner) callLuaFunction(funcName string, args ...lua.LValue) (*lua.LTable, error) {
	if !l.isStateValid() {
		return nil, fmt.Errorf("lua state is not valid")
	}

	l.mutex.RLock()
	defer l.mutex.RUnlock()

	// 调用Lua函数
	if err := l.lState.CallByParam(lua.P{
		Fn:      l.lState.GetGlobal(funcName),
		NRet:    1,
		Protect: true,
	}, args...); err != nil {
		return nil, fmt.Errorf("call %s failed: %v", funcName, err)
	}

	// 获取返回结果
	ret := l.lState.Get(-1)
	l.lState.Pop(1)

	if table, ok := ret.(*lua.LTable); ok {
		return table, nil
	}

	return nil, fmt.Errorf("unexpected return type from %s", funcName)
}

// extractByteArrayFromResult 从结果中提取字节数组
func (l *luaRunner) extractByteArrayFromResult(table *lua.LTable) ([]byte, bool) {
	result := LuaResult{}
	if err := gluamapper.Map(table, &result); err != nil {
		zap.S().Errorf("Failed to map result: %v", err)
		return nil, false
	}

	// 使用缓冲池获取字节切片
	buffer := l.bufferPool.Get().([]byte)
	buffer = buffer[:0] // 重置长度但保持容量

	// 将结果复制到缓冲区
	for _, v := range result.Variable {
		if v != nil {
			buffer = append(buffer, *v)
		}
	}

	// 创建最终的字节切片
	data := make([]byte, len(buffer))
	copy(data, buffer)

	// 归还缓冲区到池中
	l.bufferPool.Put(buffer)

	return data, result.Status != "0"
}

func (l *luaRunner) GenerateGetRealVariables(address string, step int) ([]byte, bool, bool) {
	table, err := l.callLuaFunction("GenerateGetRealVariables",
		lua.LString(address),
		lua.LNumber(step))

	if err != nil {
		zap.S().Errorf("GenerateGetRealVariables error: %v", err)
		return nil, false, false
	}

	data, continued := l.extractByteArrayFromResult(table)
	return data, len(data) > 0, continued
}

func (l *luaRunner) DeviceCustomCmd(address string, commandName string, commandParam string, step int) ([]byte, bool, bool) {
	table, err := l.callLuaFunction("DeviceCustomCmd",
		lua.LString(address),
		lua.LString(commandName),
		lua.LString(commandParam),
		lua.LNumber(step))

	if err != nil {
		zap.S().Errorf("DeviceCustomCmd error: %v", err)
		return nil, false, false
	}

	data, continued := l.extractByteArrayFromResult(table)
	return data, len(data) > 0, continued
}

// convertLuaValueToGo 优化的类型转换函数
func (l *luaRunner) convertLuaValueToGo(luaValue interface{}, targetType string, scale float64, decimal int) interface{} {
	if luaValue == nil {
		switch targetType {
		case "string":
			return ""
		default:
			return float64(0)
		}
	}

	// 应用倍率
	if scale > 0 && scale != 1 {
		if val, ok := luaValue.(float64); ok {
			luaValue = val * scale
		}
	}

	switch targetType {
	case "int":
		if val, ok := luaValue.(float64); ok {
			return int32(val)
		}
	case "uint":
		if val, ok := luaValue.(float64); ok {
			return uint32(val)
		}
	case "double":
		if val, ok := luaValue.(float64); ok {
			return val / math.Pow10(decimal)
		}
	case "string":
		if val, ok := luaValue.(string); ok {
			return val
		}
	}

	return luaValue
}

// AnalysisRxResult 包含 AnalysisRx 的完整返回结果
type AnalysisRxResult struct {
	Success      bool
	Variables    []models.DeviceProperty
	FrameType    string // login/heartbeat/data/response/command/""
	NeedResponse bool
	Response     []byte
}

func (l *luaRunner) AnalysisRx(sAddr string, variables []models.DeviceProperty, rxBuf []byte, rxBufCnt int, tempVariables *[]models.DeviceProperty) bool {
	result := l.AnalysisRxEnhanced(sAddr, variables, rxBuf, rxBufCnt)
	*tempVariables = result.Variables
	return result.Success
}

// AnalysisRxEnhanced 增强版的 AnalysisRx，返回完整信息
func (l *luaRunner) AnalysisRxEnhanced(sAddr string, variables []models.DeviceProperty, rxBuf []byte, rxBufCnt int) AnalysisRxResult {
	result := AnalysisRxResult{
		Success:   false,
		Variables: make([]models.DeviceProperty, 0),
	}

	if !l.isStateValid() {
		return result
	}

	l.mutex.RLock()
	defer l.mutex.RUnlock()

	// 创建Lua表并设置全局变量 - 优化内存分配
	table := &lua.LTable{}
	table.RawSet(lua.LNumber(0), lua.LNil) // 预分配

	for i, v := range rxBuf {
		table.RawSetInt(i+1, lua.LNumber(v))
	}
	l.lState.SetGlobal("rxBuf", table)

	// 调用AnalysisRx
	err := l.lState.CallByParam(lua.P{
		Fn:      l.lState.GetGlobal("AnalysisRx"),
		NRet:    1,
		Protect: true,
	}, lua.LString(sAddr), lua.LNumber(rxBufCnt))

	if err != nil {
		zap.S().Warnf("AnalysisRx error: %v", err)
		return result
	}

	// 获取返回结果
	ret := l.lState.Get(-1)
	if ret == nil {
		return result
	}
	l.lState.Pop(1)

	// 解析结果
	luaVariableMap := LuaVariableMap{}
	if err := gluamapper.Map(ret.(*lua.LTable), &luaVariableMap); err != nil {
		zap.S().Warnf("AnalysisRx mapping error: %v", err)
		return result
	}

	if luaVariableMap.Status != "0" {
		return result
	}

	// 提取帧类型和响应信息
	result.FrameType = luaVariableMap.FrameType
	result.NeedResponse = luaVariableMap.NeedResponse

	// 转换响应数据
	if len(luaVariableMap.Response) > 0 {
		result.Response = make([]byte, 0, len(luaVariableMap.Response))
		for _, v := range luaVariableMap.Response {
			switch val := v.(type) {
			case float64:
				result.Response = append(result.Response, byte(val))
			case int:
				result.Response = append(result.Response, byte(val))
			case int64:
				result.Response = append(result.Response, byte(val))
			}
		}
	}

	// 处理变量 - 优化查找逻辑
	variableMap := make(map[string]*models.DeviceProperty, len(variables))
	for i := range variables {
		variableMap[variables[i].Name] = &variables[i]
	}

	// 预分配临时变量切片
	if cap(result.Variables) < len(luaVariableMap.Variable) {
		result.Variables = make([]models.DeviceProperty, 0, len(luaVariableMap.Variable))
	}

	for _, lv := range luaVariableMap.Variable {
		if prop, exists := variableMap[lv.Name]; exists {
			// 使用优化的类型转换
			convertedValue := l.convertLuaValueToGo(lv.Value, prop.Type, prop.Scale, prop.Decimal)
			prop.Value = convertedValue

			// 添加到临时变量表中
			result.Variables = append(result.Variables, *prop)
		} else {
			// 如果变量不在预定义列表中，直接从 Lua 创建新变量（支持动态变量）
			newProp := models.DeviceProperty{
				Name:        lv.Name,
				Description: lv.Label,
				Type:        lv.Type,
				Value:       lv.Value,
			}
			result.Variables = append(result.Variables, newProp)
		}
	}

	result.Success = true
	return result
}

// DetectProtocol 检测数据是否匹配该协议
// Lua 函数签名: function DetectProtocol(data, dataLen) return true/false end
func (l *luaRunner) DetectProtocol(data []byte) bool {
	if !l.isStateValid() {
		return false
	}

	// 检查Lua脚本是否实现了DetectProtocol函数
	if !l.HasFunction("DetectProtocol") {
		return false
	}

	l.mutex.RLock()
	defer l.mutex.RUnlock()

	// 创建Lua表传递数据
	dataTable := &lua.LTable{}
	for i, v := range data {
		dataTable.RawSetInt(i+1, lua.LNumber(v))
	}

	// 调用DetectProtocol
	err := l.lState.CallByParam(lua.P{
		Fn:      l.lState.GetGlobal("DetectProtocol"),
		NRet:    1,
		Protect: true,
	}, dataTable, lua.LNumber(len(data)))

	if err != nil {
		return false
	}

	// 获取返回结果
	ret := l.lState.Get(-1)
	l.lState.Pop(1)

	return lua.LVAsBool(ret)
}

// ExtractDeviceAddress 从数据中提取设备地址
// Lua 函数签名: function ExtractDeviceAddress(data, dataLen) return "address" end
func (l *luaRunner) ExtractDeviceAddress(data []byte) string {
	if !l.isStateValid() {
		return ""
	}

	// 检查Lua脚本是否实现了ExtractDeviceAddress函数
	if !l.HasFunction("ExtractDeviceAddress") {
		return ""
	}

	l.mutex.RLock()
	defer l.mutex.RUnlock()

	// 创建Lua表传递数据
	dataTable := &lua.LTable{}
	for i, v := range data {
		dataTable.RawSetInt(i+1, lua.LNumber(v))
	}

	// 调用ExtractDeviceAddress
	err := l.lState.CallByParam(lua.P{
		Fn:      l.lState.GetGlobal("ExtractDeviceAddress"),
		NRet:    1,
		Protect: true,
	}, dataTable, lua.LNumber(len(data)))

	if err != nil {
		zap.S().Debugf("ExtractDeviceAddress调用失败: %v", err)
		return ""
	}

	// 获取返回结果
	ret := l.lState.Get(-1)
	l.lState.Pop(1)

	if ret.Type() == lua.LTString {
		return ret.String()
	}

	return ""
}

// GetProtocolName 获取协议名称
func (l *luaRunner) GetProtocolName() string {
	return l.filename
}

// HasFunction 检查Lua脚本是否实现了某个函数
func (l *luaRunner) HasFunction(funcName string) bool {
	if !l.isStateValid() {
		return false
	}

	l.mutex.RLock()
	defer l.mutex.RUnlock()

	fn := l.lState.GetGlobal(funcName)
	return fn.Type() == lua.LTFunction
}

// HandleActiveReport 处理主动上报事件
// 调用Lua脚本的 HandleActiveReport 函数
// Lua函数签名: function HandleActiveReport(deviceAddr, data, dataLen)
//
//	返回结构: {
//	  Success = true/false,
//	  NeedResponse = true/false,
//	  Response = {0x68, 0x00, ...},  -- 响应数据（可选）
//	  EventType = "login"/"heartbeat"/"data"/"alarm",
//	  DeviceData = {  -- 设备数据（用于更新设备状态）
//	    dev_consumption = 123.45,
//	    dev_voltage = 220.0,
//	    ...
//	  },
//	  ShouldReport = true/false  -- 是否应该上报到云端
//	}
func (l *luaRunner) HandleActiveReport(deviceAddr string, data []byte, variables []models.DeviceProperty) (EventResult, error) {
	result := EventResult{
		Success:    false,
		DeviceData: make(map[string]interface{}),
	}

	if !l.isStateValid() {
		return result, fmt.Errorf("lua state is not valid")
	}

	// 检查Lua脚本是否实现了HandleActiveReport函数
	if !l.HasFunction("HandleActiveReport") {
		return result, fmt.Errorf("HandleActiveReport function not found in lua script")
	}

	l.mutex.RLock()
	defer l.mutex.RUnlock()

	// 创建Lua表传递数据
	dataTable := &lua.LTable{}
	for i, v := range data {
		dataTable.RawSetInt(i+1, lua.LNumber(v))
	}

	// 调用HandleActiveReport
	err := l.lState.CallByParam(lua.P{
		Fn:      l.lState.GetGlobal("HandleActiveReport"),
		NRet:    1,
		Protect: true,
	}, lua.LString(deviceAddr), dataTable, lua.LNumber(len(data)))

	if err != nil {
		return result, fmt.Errorf("HandleActiveReport call failed: %v", err)
	}

	// 获取返回结果
	ret := l.lState.Get(-1)
	if ret == nil || ret.Type() != lua.LTTable {
		l.lState.Pop(1)
		return result, fmt.Errorf("HandleActiveReport returned invalid result")
	}
	l.lState.Pop(1)

	retTable := ret.(*lua.LTable)

	// 解析返回结果
	// Success
	if successVal := retTable.RawGetString("Success"); successVal != lua.LNil {
		result.Success = lua.LVAsBool(successVal)
	}

	// NeedResponse
	if needRespVal := retTable.RawGetString("NeedResponse"); needRespVal != lua.LNil {
		result.NeedResponse = lua.LVAsBool(needRespVal)
	}

	// Response (字节数组)
	if respVal := retTable.RawGetString("Response"); respVal != lua.LNil {
		if respTable, ok := respVal.(*lua.LTable); ok {
			response := make([]byte, 0, respTable.Len())
			respTable.ForEach(func(k, v lua.LValue) {
				if num, ok := v.(lua.LNumber); ok {
					response = append(response, byte(num))
				}
			})
			result.Response = response
		}
	}

	// EventType
	if eventTypeVal := retTable.RawGetString("EventType"); eventTypeVal != lua.LNil {
		result.EventType = lua.LVAsString(eventTypeVal)
	}

	// DeviceData (map)
	if deviceDataVal := retTable.RawGetString("DeviceData"); deviceDataVal != lua.LNil {
		if deviceDataTable, ok := deviceDataVal.(*lua.LTable); ok {
			deviceDataTable.ForEach(func(k, v lua.LValue) {
				key := lua.LVAsString(k)

				// 根据值类型转换
				switch v.Type() {
				case lua.LTNumber:
					result.DeviceData[key] = float64(lua.LVAsNumber(v))
				case lua.LTString:
					result.DeviceData[key] = lua.LVAsString(v)
				case lua.LTBool:
					result.DeviceData[key] = lua.LVAsBool(v)
				default:
					result.DeviceData[key] = v.String()
				}
			})
		}
	}

	// ShouldReport
	if shouldReportVal := retTable.RawGetString("ShouldReport"); shouldReportVal != lua.LNil {
		result.ShouldReport = lua.LVAsBool(shouldReportVal)
	} else {
		// 默认应该上报
		result.ShouldReport = true
	}

	return result, nil
}

// InitPluginManager 初始化插件管理器（在启动时调用）
func InitPluginManager(lifecycle fx.Lifecycle) *PluginManager {
	pm := GetPluginManager()

	// 注册生命周期钩子
	lifecycle.Append(fx.Hook{
		OnStop: func(ctx context.Context) error {
			zap.S().Info("关闭插件管理器...")
			pm.Close()
			return nil
		},
	})

	return pm
}

var Module = fx.Options(
	fx.Provide(NewLuaRunner),
	fx.Provide(InitPluginManager), // 提供 PluginManager 给其他模块使用
)
